package masterlink.sarPoint;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.LinkedBlockingQueue;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.icetech.ipush.ICEException;
import com.icetech.ipush.iPushLink;
import com.icetech.ipush.ipushmsg;
import com.icetech.quoteclient.jQuoteLink;

import masterlink.sarPoint.process.Worker;
import masterlink.sarPoint.process.Tick;
import masterlink.sarPoint.source.FileHandler;
import masterlink.sarPoint.source.IpushHandler;
import masterlink.sarPoint.util.Util;
import masterlink.sarPoint.vo.FitxTick;
import masterlink.sarPoint.vo.MKLine;
import com.icetech.quoteclient.jQuoteMsg;
public class Start implements ipushmsg{
	private static final Logger log=LoggerFactory.getLogger(Start.class);
	public static iPushLink iPush;
	private static Properties ini=new Properties();
	private static final String defaultIni="ini/sarPoint.ini";
	private static LinkedBlockingQueue<Object> queue=new LinkedBlockingQueue<Object>();
	public static Map<Integer,FitxTick> td = new HashMap<Integer,FitxTick>();//存放當日K線資料
	public static ArrayList<Integer> runEMA = new ArrayList<Integer>();//取得設定檔EMA的資料, 30, 60
	public static ArrayList<Integer> runSAR = new ArrayList<Integer>();//取得設定檔SAR的資料, 2, 20, 20
	private static final List<Thread> active=new ArrayList<Thread>();
	public static List<MKLine> lmk = new ArrayList<MKLine>();//存放K線資料(當日+非當日),供計算使用
	public static ArrayList<String> ipushParam = new ArrayList<String>();
	public static final List<MKLine> pPoint = new ArrayList<MKLine>();
	private static File iniFile;
	private static int state=0;
	private static int totQty=0;//修正成交口數差異, 18:成交量, 19:總成交量
	public static int curPnt=0;//目前所在時間TICK點
	public static int KLine=1;//計算幾分K線
	private static int count=0;
	private static final int overtime=1345;
	public static final String dateTag="20130304";
	public static void main(String[] args){
		Start st = new Start();
		if(args.length>0){
			iniFile=new File(args[0]);
		}else{
			iniFile=new File(defaultIni);
		}
		try{
			log.info("Loading iniFile from : {}",iniFile.getAbsolutePath());
			ini.load(new FileReader(iniFile));
			setEnv();
//			st.DoConnect();
			genHisData();
			startThreads();
			monitor();
		}catch (Exception e) {
			log.error("Error happen! ",e);
			state=-1;
		}finally{
			System.exit(state);
		}
	}
	private static void setEnv(){
		//產生幾分K線
		KLine=getIntProperty("KLine",1);
		log.info("設定:{}分K線",KLine);
		//加入移動平均線
		String ema = getStringProperty("runEMA","|30|60|");
		String eema[]=ema.split("[|]");
		for(int i=1;i<eema.length;i++){
			log.info("設定:"+eema[i]+"移動平均線");
			runEMA.add(Integer.parseInt(eema[i]));	
		}
		String sar = getStringProperty("runSAR","|2|20|20|");
		String ssar[]=sar.split("[|]");
		for(int i=1;i<ssar.length;i++){
			log.info("設定:"+ssar[i]+"SAR");
			runSAR.add(Integer.parseInt(ssar[i]));
		}
//		ipush=|192.168.5.131|443|Masterlink|WT5|client|ml2856|%TiWT5.Rother|%TiWT5.Oother|
		String ipushStr = getStringProperty("ipush","");
		String str[]=ipushStr.split("[|]");
		for(String stra:str){
			ipushParam.add(stra);
		}

	}
	private static void genHisData(){
		log.trace("GenHisData start");
		String str;
		int cnt=0;
		BufferedReader br=null;
		try{
			br = new BufferedReader(new FileReader("C:/java/data/hData.txt"));
			MKLine mkl=new MKLine();
			while(true){
				str = br.readLine();
				if(str==null){
					break;
				}
				String b[] = str.split("[|]");
				cnt++;
				mkl.setCtime(Integer.parseInt(b[0]));
				mkl.setoPrice(Integer.parseInt(b[2]));
				mkl.sethPrice(Integer.parseInt(b[3]));
				mkl.setlPrice(Integer.parseInt(b[4]));
				mkl.setcPrice(Integer.parseInt(b[5]));
				mkl.setPrice(Long.parseLong(b[7]));
				mkl.setQty(Integer.parseInt(b[6]));
				if(cnt%KLine==0){
					lmk.add(mkl);
					mkl = new MKLine();
				}
			}
		}catch(Exception e){
			log.error("error:{}",e);
		}
		log.trace("GenHisData end");
	}
	/**
	 * 依序啟動Worker Thread, Ipush Thread及Jms Thread.
	 *
	 */
	private static void startThreads() {
		startWorker();
		startFile();
		startTick();
//		startIpush();
	}
	private static void startTick(){
		log.info("Start Tick Display thread");
		Tick tick = new Tick();
		tick.start();
		active.add(tick);
	}
	private static void startFile(){
		log.info("Start FileHandler thread!");
		FileHandler fh = new FileHandler();
		fh.start();
		active.add(fh);
	}
	/**
	 * 啟動Worker Thread.
	 *
	 */
	private static void startWorker(){
		log.info("Start Worker thread!");
		Worker worker=new Worker();
		worker.start();
		active.add(worker);
	}
	/**
	 * 啟動Ipush Thread
	 *
	 */
	private static void startIpush(){
		log.info("Start IpushHandler thread!");
		IpushHandler ipush=new IpushHandler();
		ipush.start();
	}
	/**
	 * TODO write the document
	 *
	 * @throws InterruptedException
	 */
	private static void monitor() throws InterruptedException {
		int wait=getIntProperty("MONITOR_WAIT_MS",15000);
		if(wait>0){
			while(true){
				Thread.sleep(wait);
				if(active.isEmpty()){
					log.debug("No active thread found! System exit.");
					break;
				}
				log.info("Active Threads: {}, Queue Count: {}",active.size(), queue.size());
			}
		}else{
			synchronized (active) {
				active.wait();
			}
		}
	}
	/**
	 * 取得設定檔裡key的值(String), 如果找不到對應的key時就回傳defaultV.
	 *
	 * @param key
	 * @param defaultV
	 * @return
	 */
	public static String getStringProperty(String key,String defaultV){
		return ini.getProperty(key)==null?defaultV:ini.getProperty(key);
	}
	/**
	 * 取得設定檔裡key的值(int), 如果找不到對應的key時就回傳defaultI.
	 *
	 * @param key
	 * @param defaultI
	 * @return
	 */
	public static int getIntProperty(String key,int defaultI){
		return ini.getProperty(key)==null?defaultI:Integer.valueOf(ini.getProperty(key));
	}

	/**
	 * 將物件加入到FIFO queue裡等待Worker處理.
	 *
	 * @param obj
	 */
	public static void put(Object obj){
		synchronized (queue) {
			if(queue.add(obj)){
				queue.notify();
			}
		}
	}
	/**
	 * 從FIFO queue取得物件.
	 *
	 * @return
	 * @throws InterruptedException
	 */
	public static Object poll() throws InterruptedException{
		synchronized (queue) {
			if(queue.isEmpty()){
				queue.wait();
			}
			return queue.poll();
		}
	}
	/**
	 * 把資料放到Tick的MAP裡面去
	 * @return 
	 */
	public static boolean setTickM(int time,int price,int qty,int sumqty,int minute){
		FitxTick ft;
		boolean tag=false;
		if(qty+totQty<sumqty){
			qty=sumqty-totQty;
		}
		if(sumqty>totQty){
			totQty=sumqty;
		}else{
			log.info("time:{}",time);
		}
		int tick = Util.compTimeNum(time/10000);
		tick = tick/minute;
		if(time/10000==overtime){
			tick=(tick/minute)-1;
		}
		if(time/10000>overtime){
			return false;
		}
		if(td.containsKey(tick)){
			ft = td.get(tick);
		}else{
			tag = true;
//			log.info("tick:{}, time:{}",tick,time);
			ft = new FitxTick();
		}
		curPnt = tick;
		ft.setData(time, price/1000, qty);
		td.put(tick,ft);
		return tag;
	}
	/**
	 * 把資料放到Tick的MAP裡面去
	 * @return 
	 */
	public static boolean setTick(int time,int price,int qty,int sumqty){
		FitxTick ft;
		boolean tag=false;
		if(qty+totQty<sumqty){
			qty=sumqty-totQty;
		}
		if(sumqty>totQty){
			totQty=sumqty;
		}else{
			log.info("time:{}",time);
		}
		int tick = Util.compTimeNum(time/10000);
		if(time/10000==overtime){
			tick=tick-1;
		}
		if(time/10000>overtime){
			return false;
		}
		if(td.containsKey(tick)){
			ft = td.get(tick);
		}else{
			tag = true;
//			log.info("tick:{}, time:{}",tick,time);
			ft = new FitxTick();
		}
		curPnt = tick;
		ft.setData(time, price/1000, qty);
		td.put(tick,ft);
		return tag;
	}
	/**
	 * 取出第幾根分K資料
	 * @return 分K資料
	 */
	public static FitxTick getTick(int tick){
		FitxTick ft;
		if(td.containsKey(tick)){
			ft = td.get(tick);
		}else{
			ft = null;
		}
		return ft;
		
	}
	@Override
	public void doBlockMessage(byte id[],int idlen,String name,byte msg[],int len) {
		log.debug("block message: {} length={}",name,len);
		
	}
	@Override
	public void doError(String buf) {
		log.debug(buf);
	}
	@Override
	public void doMessage(byte id[],int idlen, byte msg[],int len) {
		String channel=new String(id,0,idlen);
	    String message="";
	    log.debug("Channel: {}\n Message: {}",channel,message);
		
	}
	@Override
	public void onException(ICEException e) {
	    System.out.println(e.getMessage());
	    switch(e.code){
	    case 1://偵測連線成功
	    	DoReSubject();
	    	break;
	      case 3:
	      case 21:
	      case 31:
//	        DoConnect();
	        DoReSubject();
	        break;
	      case 20:
	      case 30:
	        System.out.println("e.code = "+e.code+" , "+e.getMessage()+" "+e.param);
	        break;
	      default:
	        System.out.println("e.code = "+e.code+" , "+e.getMessage());
	        break;
	    }
	}
	//接收資料
	@Override
	public void doSubjectMessage(String subject,byte msg[],int len) {
		count++;
		log.debug("subject:{}, data:{}",subject,new String(msg,0,len));
	}
	public void DoConnect(){
		iPush = new iPushLink();
		boolean tag=false;
//		ipush=|192.168.5.131|443|Masterlink|WT5|client|ml2856|%TiWT5.Rother|%TiWT5.Oother|
		tag = iPush.netConnect(this,ipushParam.get(1),Integer.parseInt(ipushParam.get(2)), ipushParam.get(3),
				ipushParam.get(4),ipushParam.get(5),ipushParam.get(6));
		log.info("reConnect :"+tag+","+ipushParam.get(1)+","+ipushParam.get(2)+","+ipushParam.get(3)+","+
				ipushParam.get(4)+","+ipushParam.get(5)+","+ipushParam.get(6));
	}
	private void DoReSubject(){
		log.trace("DoReSubject");
		try{
			Thread.sleep(2000);
		}catch(Exception ie){
			log.error("Threadexception:{}",ie);
		}
		iPush.subscribeSubject(ipushParam.get(8));//進行註冊到ipush上面,這樣才能接收到資料
		log.trace("DoReSubject={}",ipushParam.get(8));
	}
}
